package org.geom.render;

import java.awt.Dimension;
import java.util.ArrayList;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLJPanel;
import javax.media.opengl.glu.GLU;
import javax.swing.border.TitledBorder;

import mvc.ControllerMouse3D;

import org.geom.Vector3D;

public abstract class ViewJOGL extends GLJPanel 
implements GLEventListener, IRenderer {	private static final long serialVersionUID = 1L;

	//---------------------------------------------------------------------- classvar
	protected Vector3D t_offset = new Vector3D();
	protected Vector3D r_offset = new Vector3D();
	protected Vector3D s_offset = new Vector3D(1,1,1);//0.01,0.01,0.01);
	
	public final GLU glu = new GLU();

	//---------------------------------------------------------------------- constructor
	public ViewJOGL(Dimension d) {
		super();
		this.setBorder(new TitledBorder("foo"));
		this.setPreferredSize(d);
		this.setVisible(true);
		this.addGLEventListener(this);
	}

	//---------------------------------------------------------------------- JOGL implementation
	@Override
	public void init(GLAutoDrawable drawable) {
		final GL gl = drawable.getGL();
		gl.glShadeModel(GL.GL_SMOOTH);
		gl.glClearColor(0.6f, 0.6f, 0.6f, 0.6f);
		gl.glClearDepth(1.0f);
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthFunc(GL.GL_LEQUAL);
		gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
	}

	@Override
	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		final GL gl = drawable.getGL();

		if (height <= 0) // avoid a divide by zero error!
			height = 1;
		final float h = (float) width / (float) height;
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(45.0f, h, 1.0f, 2000.0f);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
	}	

	@Override
	public void display(GLAutoDrawable drawable) {		
		//System.out.println("EngingJOGL > display");
		final GL gl = drawable.getGL();
		
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glLoadIdentity();
		
		gl.glTranslatef(0,0,-400);
		gl.glTranslatef(t_offset.x, -t_offset.y, 0);
		
		gl.glRotatef(r_offset.x, 0, 1, 0);
		gl.glRotatef(r_offset.y, 1, 0, 0);
		
		gl.glScalef(s_offset.x, s_offset.x, s_offset.x);
		
		render(gl);
	}
	
	public abstract void render(GL gl);
	
	@Override
	public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) {}

	//---------------------------------------------------------------------- IRender implementation

	public void render() {
		this.repaint(); //TODO: togliere dall'interfaccia?
	}
	
	@Override
	public Vector3D getRotate() {
		return this.r_offset;
	}

	@Override
	public Vector3D getScale() {
		return this.s_offset;
	}

	@Override
	public Vector3D getTranslate() {
		return this.t_offset;
	}

	@Override
	public void setRotate(Vector3D r) {
		this.r_offset = r;
	}

	@Override
	public void setScale(Vector3D s) {
		// only x is parsed
		float new_s = s_offset.x + s.x; 
		if(new_s<2f && new_s>-7f)
			s_offset.x = new_s;
		else 
			System.out.println("ViewJOGL > setScale > "+s_offset.x);
	}

	@Override
	public void setTranslate(Vector3D t) {
		this.t_offset = t;		
	}

	@Override
	public void setViewPort(Dimension d) {
		setPreferredSize(d);
		render();
	}


	//---------------------------------------------------------------------- utils and IRenderer
	
	protected void drawCenter(GL gl) {
		gl.glPushMatrix();
		gl.glScalef(10, 10, 10);

		gl.glBegin(GL.GL_LINE);
		gl.glColor3f(0, 0, 0);
		gl.glVertex3i(0, 0, 0);
		gl.glVertex3i(1, 1, 0);

		gl.glColor3f(0, 0, 0);
		gl.glVertex3i(0, 0, 0);
		gl.glVertex3i(1, 0, 1);

		gl.glColor3f(0, 0, 0);
		gl.glVertex3i(0, 0, 0);
		gl.glVertex3i(0, 1, 1);
		gl.glEnd();

		gl.glPopMatrix();
	}

	protected void drawPoints(ArrayList<Vector3D> points, GL gl) {
		gl.glPushMatrix();
		
		gl.glBegin(GL.GL_LINE_STRIP);
		gl.glColor3f(1.0f,1.0f,1.0f);
		for (Vector3D p : points) {
			gl.glVertex3f(p.x, p.y, p.z);	
		}
		gl.glEnd();
		
		gl.glPopMatrix();
	}

	protected void drawCurvePoints(ArrayList<Vector3D> points, GL gl) {
		int k = 2;

		gl.glPushMatrix();
		
		gl.glColor3f(0.3f,0.3f,0.3f);
		gl.glPointSize(k);
		gl.glBegin(GL.GL_POINT);
		for (Vector3D p : points) {
			gl.glVertex3d(p.x, p.y, p.z);
		}
		gl.glEnd();
		
		gl.glPopMatrix();
	}

	public void drawCurve(ArrayList<Vector3D> points, GL gl) {
		gl.glColor3f(1.0f,0.0f,0.0f);
		gl.glBegin(GL.GL_LINE_STRIP);
		for (Vector3D p : points) {
			gl.glVertex3d(p.x, p.y, p.z);
		}
		gl.glEnd();
	}
	
	public void addMouseKeybController(ControllerMouse3D controller3d) {
		addMouseListener(controller3d);
		addMouseMotionListener(controller3d);
		addKeyListener(controller3d);
	}
	
}
